/*******************************************************************************
 * Copyright (c) 2006 CEA LIST.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA LIST - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.tabbedproperties;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.views.properties.tabbed.AbstractPropertySection;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.uml.NamedElement;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.ui.dialogs.ElementTreeSelectionDialog;
import com.cea.papyrus.core.utils.LookForElement;

/**
 * 
 * @author Patrick Tessier
 * This is an Abstract class use to display a label with the referenced named Element 
 * For example type of a property
 *
 */
public abstract class AbstractSelectionElementSection extends PropertyViewSection {

	/**
	 * the label to display in the la bel
	 */
	private String labelToDisplay="";
	/**
	 * the filter to look for a good element
	 */
	private ViewerFilter filter;

	/**
	 * the constructor of this display
	 * @param labeltoDisplay use to display the name is the label
	 * @param filter use to look for the good element
	 */
	public AbstractSelectionElementSection(String labeltoDisplay,ViewerFilter filter ) {
		super();
		this.labelToDisplay=labeltoDisplay;
		this.filter=filter;
	}


	/** Buttons used in the section */
	protected Button browseButton, removeButton; 

	/** Associated label */
	protected CLabel label;

	/** The parent Composite */
	protected Composite parent;

	/** Listener for the delete button */
	protected MouseListener removeButtonListener;

	/** Listener for the browse button */
	protected MouseListener browseButtonListener;

	/** Image for the remove button */
	protected final org.eclipse.swt.graphics.Image remove_img = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"Delete_16x16.gif");

	/** Image for the add button */
	protected final org.eclipse.swt.graphics.Image add_img = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"Add_16x16.gif");

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#createControls(org.eclipse.swt.widgets.Composite, org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
	 */
	@Override
	public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);
		Composite composite = getWidgetFactory().createFlatFormComposite(parent);
		this.parent = parent;
		FormData data;

		//removeButton layout
		removeButton = getWidgetFactory().createButton(composite, "", SWT.PUSH);
		removeButton.setImage(remove_img);
		data = new FormData();
//		data.left = new FormAttachment(browseButton, ITabbedPropertyConstants.HSPACE);
		data.right = new FormAttachment(100, -ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(0, ITabbedPropertyConstants.HSPACE);
		removeButton.setLayoutData(data);

		//browseButton layout
		browseButton = getWidgetFactory().createButton(composite, "", SWT.PUSH);
		browseButton.setImage(add_img);
		data = new FormData();
		data.right = new FormAttachment(removeButton, -ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(0, ITabbedPropertyConstants.HSPACE);
		browseButton.setLayoutData(data);

		//label creation
		final CLabel displayLabel = getWidgetFactory().createCLabel(composite, labelToDisplay); //$NON-NLS-1$
		data = new FormData();
		data.left = new FormAttachment(0, 0);
		data.top = new FormAttachment(0, ITabbedPropertyConstants.HSPACE);
		displayLabel.setLayoutData(data);
		
		//value label
		label = getWidgetFactory().createCLabel(composite, "", SWT.BORDER);
		data = new FormData();
		data.left = new FormAttachment(0, AbstractPropertySection.STANDARD_LABEL_WIDTH+ITabbedPropertyConstants.HSPACE);
		data.right = new FormAttachment(browseButton, -ITabbedPropertyConstants.HSPACE);
		data.top = new FormAttachment(0, ITabbedPropertyConstants.HSPACE);
		label.setLayoutData(data);

		//listeners setting
		browseButtonListener = new BrowseButtonlistener();
		browseButton.addMouseListener(browseButtonListener);
		removeButtonListener = new RemoveButtonlistener();
		removeButton.addMouseListener(removeButtonListener);
	}
	/**
	 * this method is used to get the element that we want to display 
	 * use ((Property)getElement()).getType()
	 * @return the named Element
	 */
	public abstract NamedElement getReferencedElementToDisplay();
	/**
	 * use to perform action to clean the element 
	 * for example ((Property)getElement()).setType(null)
	 */
	public abstract void removeReferencedElement();
	/**
	 * use to set the new Element
	 * for example( (Property)getElement()).setType((Type) element)
	 * @param element the element that will be set
	 */
	public abstract void setReferencedElement(NamedElement element);

	/**
	 * Refreshes the section.
	 */
	@Override
	public void refresh(){
		if(!browseButton.isDisposed()){
			NamedElement namedElement = getReferencedElementToDisplay();
			// if no operation has already attached to the CallOperationAction,
			// the default text is displayed.
			if(namedElement == null){
				if(!label.isDisposed())
					label.setText("<UNDEFINED>");
				if(!removeButton.isDisposed())
					removeButton.setEnabled(false);
			}
			// else the qualified name of the operation attached to the CallActionOperation is displayed.
			else{
				if(!label.isDisposed())
					label.setText(namedElement.getQualifiedName());
				if(!removeButton.isDisposed())
					removeButton.setEnabled(true);
			}
		}
	}

	/**
	 * Listener for the RemoveButton.
	 * Specific behavior is implemented in removeButtonPressed.
	 */
	protected class RemoveButtonlistener implements MouseListener{

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDoubleClick(MouseEvent e){
		}

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDown(MouseEvent e){
		}

		/**
		 * Calls the removeButtonPressed() which does the job then refresh().
		 * @param e MouseEvent.
		 */
		public void mouseUp(MouseEvent e){
			removeButtonPressed();
			refresh();
		}
	}

	/**
	 * Listener for the BrowseButton.
	 * Specific behavior is implemented in browseButtonPressed.
	 */
	protected class BrowseButtonlistener implements MouseListener{

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDoubleClick(MouseEvent e){
		}

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDown(MouseEvent e){
		}

		/**
		 * Calls the browseButtonPressed() which does the job then refresh().
		 * @param e MouseEvent.
		 */
		public void mouseUp(MouseEvent e){
			browseButtonPressed();
			refresh();
		}
	}

	/**
	 * Behavior executed when remove button is pressed.
	 */
	protected void removeButtonPressed(){
		removeReferencedElement();
	}

	/**
	 * Behavior executed when browse button is pressed.
	 */
	protected void browseButtonPressed(){
		final int[] result = {IDialogConstants.CANCEL_ID};

		//create filter to choose operation
		ViewerFilter[] filters={this.filter};

		//create the dialog box for selecting one operation in the model
		final ElementTreeSelectionDialog elementSelectionDialog =
			new ElementTreeSelectionDialog(parent.getShell(),
					LookForElement.topPackage(getElement()),
					modelManager,filters,"Select "+labelToDisplay);

		// open busy dialog window when loading the operationSelectionDialog
		BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
			public void run() {
				result[0] = elementSelectionDialog.open();
			}
		});

		// if ok button is pressed, and an operation is selected,
		// the selected operation is then set to the CallActionOperation
		if(IDialogConstants.OK_ID == result[0]){
			//get selected operation
			if (elementSelectionDialog.getResult() instanceof NamedElement){
				setReferencedElement((NamedElement)elementSelectionDialog.getResult());
			}
		}
	}

	/**
	 * Disposes of the buttons and listeners. 
	 */
	public void dispose(){
		if((removeButton != null) && !removeButton.isDisposed()) {
			removeButton.removeMouseListener(removeButtonListener);
		}
		if((browseButton != null) && !browseButton.isDisposed()) {
			browseButton.removeMouseListener(browseButtonListener);
		}
		super.dispose();
	}
}